#include "Task.hpp"
#include "Channel.hpp"

using namespace std;

using work_t = function<void()>;

enum
{
    OK = 0,
    UsageError,
    PipeError,
    ForkError
};

class ProcessPool
{
public:
    ProcessPool(int n, work_t w)
        : procesnum(n), work(w)
    {
    }

    // channels：输出型参数
    int InitProcessPool()
    {
        for (int i = 0; i < procesnum; ++i)
        {
            // 1.先有管道
            int pipefd[2] = {0};
            int n = pipe(pipefd); // 创建管道
            if (n < 0)
                return PipeError; // 创建失败

            pid_t id = fork();
            if (id < 0)
                return ForkError;

            if (id == 0)
            {
                //关闭历史的wfd
                cout << getpid() << ", child close history fd: ";
                for (auto& c : channels)
                {
                    cout << c._wFd() << " ";
                    c.Close();
                }
                cout << " over" << endl;
                ::close(pipefd[1]); // 子进程关闭写
                // child
                // 重定向之前先看对应读端的文件描述符
                cout << "debug:" << pipefd[0] << endl;
                // 重定向
                dup2(pipefd[0], 0);
                work(); // 调用对应方法
                exit(0);
            }

            // 父进程执行
            ::close(pipefd[0]); // 父进程关闭读
            channels.emplace_back(pipefd[1], id);
            // Channel ch(pipefd[1], id);
            // channels.push_back(ch);//相当于把写端管理起来
        }

        return OK;
    }

    void DebugPrint()
    {
        for (const auto &c : channels)
        {
            cout << c.Name() << endl;
        }
    }

    void DispatchTask()
    {
        int who = 0;
        int num = 10; // 假设一共10个任务
        // 2.派发任务
        while (num--)
        {
            // a.选择一个任务，整数
            int task = tmg.SelectTask();
            // b.选择一个子进程 channel 轮询策略
            Channel &curr = channels[who++];
            who %= channels.size();

            cout << "##############" << endl;
            cout << "send " << task << " to" << curr.Name() << ", 任务还剩:" << num << "个" << endl;
            cout << "##############" << endl;

            // c.派发任务
            curr.Send(task);
            sleep(1); // 每1s发送一次任务
        }
    }

    void CleanProcessPool()
    {
        // version 3
        for (auto &c : channels)
        {
            c.Close();
            pid_t rid = ::waitpid(c.Id(), nullptr, 0); // 阻塞了
            // 等待成功返回子进程pid
            if (rid > 0)
            {
                cout << "child:" << rid << " wait ... success" << endl;
            }
        }

        // version 2
        // for (int i = channels.size() - 1; i >= 0; --i)
        // {
        //     channels[i].Close();
        //     pid_t rid = ::waitpid(channels[i].Id(), nullptr, 0);  //阻塞了
        //     // 等待成功返回子进程pid
        //     if (rid > 0)
        //     {
        //         cout << "child:" << rid << " wait ... success" << endl;
        //     }
        // }

        // version 1
        // for (auto &c : channels)
        // {
        //     c.Close();
        // }

        // // 还要回收对应的子进程
        // for (auto &c : channels)
        // {
        //     // 第一个参数指定子进程 第二个参数获取子进程退出信息 第三个参数阻塞等待
        //     pid_t rid = ::waitpid(c.Id(), nullptr, 0);
        //     // 等待成功返回子进程pid
        //     if (rid > 0)
        //     {
        //         cout << "child:" << rid << " wait ... success" << endl;
        //     }
        // }
    }

private:
    vector<Channel> channels;
    int procesnum;
    work_t work;
};
